#!/usr/bin/env bash
set -Eeuo pipefail

# --- Step 1: MIL compatibility check (major version must match this package) ---
# Each Agent package targets ONE MIL major version (MIL 3 = Debian 11, MIL 4 = Debian 13).
# Installing the wrong MIL build causes unmet dependencies / a non-running agent, so refuse
# early and point to the correct package instead of letting apt fail with a cryptic error.
EXPECTED_MIL_MAJOR=4
MIN_MIL_VER="4.0.0"

if ! command -v mx-ver >/dev/null 2>&1; then
  echo "ERROR: Could not find mx-ver command. Please run this script in a MIL environment."
  exit 1
fi

MIL_VER="$(mx-ver -M 2>/dev/null | tr -d '[:space:]')"
if [ -z "${MIL_VER:-}" ]; then
  echo "ERROR: Failed to detect MIL version."
  exit 1
fi

DEV_MIL_MAJOR="${MIL_VER%%.*}"
if [ "$DEV_MIL_MAJOR" != "$EXPECTED_MIL_MAJOR" ]; then
  echo "ERROR: This package is for MIL ${EXPECTED_MIL_MAJOR}.x, but this device is MIL ${MIL_VER}."
  echo "       Use the MIL${DEV_MIL_MAJOR} Agent package instead (DLM_Agent_MIL${DEV_MIL_MAJOR}_<your model>)."
  exit 1
fi

# Minimum supported patch level within this MIL major
if ! dpkg --compare-versions "$MIL_VER" ge "$MIN_MIL_VER"; then
  echo "ERROR: Current MIL version is ${MIL_VER} (below ${MIN_MIL_VER}). This package requires MIL >= ${MIN_MIL_VER}. Exiting."
  exit 1
fi

# --- Extra: check user.yaml & cert.pem in script directory when TLS verification is enabled ---

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
USER_YAML="${SCRIPT_DIR}/user.yaml"
LOCAL_CERT="${SCRIPT_DIR}/cert.pem"

# --- CPU architecture check: refuse a package built for a different arch ---
# dpkg would refuse a mismatched arch at install time anyway, but fail early with a clear message.
SYS_ARCH="$(dpkg --print-architecture 2>/dev/null || true)"
AGENT_DEB="$(ls "${SCRIPT_DIR}"/moxa-dlm-agent_*.deb 2>/dev/null | head -n1 || true)"
if [ -n "${AGENT_DEB:-}" ] && command -v dpkg-deb >/dev/null 2>&1; then
  PKG_ARCH="$(dpkg-deb -f "$AGENT_DEB" Architecture 2>/dev/null || true)"
  if [ -n "${PKG_ARCH:-}" ] && [ "$PKG_ARCH" != "all" ] && [ "$PKG_ARCH" != "${SYS_ARCH}" ]; then
    echo "ERROR: This package is built for '${PKG_ARCH}', but this device is '${SYS_ARCH}'."
    echo "       Use the Agent package that matches your device:"
    echo "         UC-8200                            = armhf (32-bit)"
    echo "         UC-1200A/2200A/3400A/4400A/8600A   = arm64 (64-bit)"
    exit 1
  fi
fi

if [ -f "$USER_YAML" ]; then
  # Extract skipTLSVerify value (e.g., true / false)
  SKIP_TLS="$(awk -F: '/skipTLSVerify/{gsub(/[[:space:]]/,"",$2); print $2; exit}' "$USER_YAML" || true)"

  if [ "$SKIP_TLS" = "false" ]; then
    if [ ! -f "$LOCAL_CERT" ]; then
      echo "ERROR: security.skipTLSVerify is false in user.yaml, but cert.pem is missing in ${SCRIPT_DIR}."
      echo "Please place cert.pem in the same directory as this run script and user.yaml."
      echo "The certificate(cert.pem) is located under /var/lib/dlm/data/certs/root/ on the DLM server."
      exit 1
    fi
  fi
fi

set -Eeuo pipefail

# ======================
# Pretty logging helpers
# ======================
if [ -t 1 ]; then
  GREEN="\e[32m"; YELLOW="\e[33m"; RED="\e[31m"; CYAN="\e[36m"; BOLD="\e[1m"; DIM="\e[2m"; RESET="\e[0m"
else
  GREEN=""; YELLOW=""; RED=""; CYAN=""; BOLD=""; DIM=""; RESET=""
fi

log_info()  { echo -e "  ${GREEN}[INFO]${RESET} $*"; }
log_warn()  { echo -e "  ${YELLOW}[WARN]${RESET} $*"; }
log_error() { echo -e "  ${RED}[ERROR]${RESET} $*"; }
log_step()  { echo -e "${CYAN}${BOLD}Step ${CURRENT_STEP}/${TOTAL_STEPS}:${RESET} $*"; }

sep()       { echo -e "${DIM}------------------------------------------------------------${RESET}"; }

on_error() {
  log_error "Installation failed on Step ${CURRENT_STEP}. See messages above."
  echo
  exit 1
}
trap on_error ERR

# ======================
# Config
# ======================
AGENT_DIR="/etc/moxa/moxa-dlm-agent"
AGENT_SERVICE="moxa-dlm-agent"
USER_FILE="${AGENT_DIR}/user.yaml"
CERT_PEM="${AGENT_DIR}/cert.pem"
CREDENTIALS_ENC="${AGENT_DIR}/private/credentials.enc"

TOTAL_STEPS=7
CURRENT_STEP=0

# ======================
# Step 0: Header
# ======================
echo
sep
echo -e "${BOLD}Moxa DLM Agent Setup${RESET}"
sep
echo

# ======================
# Pre-flight guard: this is an INSTALL / ENROLL script. On a device that is
# ALREADY enrolled it will clear the enrollment token (Step 1) and re-import
# credentials (Step 6) — i.e. RE-ENROLL it. Run this check BEFORE any of that:
#   • automation / non-interactive  -> always STOP (never re-enroll silently)
#   • interactive operator          -> warn and ask to continue
#   • --reinstall / --force          -> skip the prompt (explicit intent)
# ======================
FORCE_REINSTALL=0
for _arg in "$@"; do
  case "$_arg" in --reinstall|--force) FORCE_REINSTALL=1 ;; esac
done

if [ -f "$CREDENTIALS_ENC" ] && [ "$FORCE_REINSTALL" -ne 1 ]; then
  log_warn "This device already has a DLM Agent enrolled.  ${DIM}(found ${CREDENTIALS_ENC})${RESET}"
  echo    "  Continuing will RE-ENROLL it: the enrollment token is cleared and the credentials"
  echo    "  are re-imported from the user.yaml + credentials.yaml in this folder."
  echo
  if [ -t 0 ]; then
    # Interactive operator — ask before doing anything destructive.
    echo -e "  ${BOLD}Make sure BOTH files are filled correctly first${RESET}, or the device may fail to reconnect:"
    echo    "    • user.yaml        -> dlmServer.host = your DLM server FQDN (no https://)"
    echo    "    • credentials.yaml -> a valid enrollment account (email / password)"
    echo
    printf  "  Continue and RE-ENROLL this device? [y/N] "
    read -r _ans </dev/tty 2>/dev/null || _ans=""
    case "$_ans" in
      y|Y|yes|YES) echo; log_info "Proceeding with re-enrollment as requested." ;;
      *) echo; log_info "Aborted — no changes were made."; echo; exit 1 ;;
    esac
  else
    # Non-interactive (automation / Swift / piped) — never re-enroll silently.
    log_error "Refusing to run unattended on an already-enrolled device."
    echo    "  • To UPDATE an enrolled device, use the '2_Update_On_Device' package"
    echo    "    (it upgrades the agent + MIL components and keeps the enrollment & credentials)."
    echo    "  • To re-enroll unattended on purpose, pass:  ./run --reinstall"
    echo
    sep
    exit 1
  fi
  echo
fi

# ======================
# Step 1: Ensure dirs & clear old token
# ======================
CURRENT_STEP=$((CURRENT_STEP+1))
log_step "Prepare agent directory & remove old tokens"
mkdir -p "$AGENT_DIR"
chmod 700 "$AGENT_DIR"
chown root:root "$AGENT_DIR"
log_info "Ensured ${AGENT_DIR} exists with 700 perms (root:root)."

if compgen -G "/etc/remoteagent/certs/*" > /dev/null 2>&1; then
  rm -rf /etc/remoteagent/certs/*
  log_info "Cleared /etc/remoteagent/certs/*"
else
  log_info "No legacy tokens in /etc/remoteagent/certs (nothing to clear)."
fi
echo

# ======================
# Step 2: Install or keep user.yaml
# ======================
CURRENT_STEP=$((CURRENT_STEP+1))
log_step "Install or keep user.yaml"
if [ -f ./user.yaml ]; then
  log_info "Installing user.yaml -> ${USER_FILE}"
  cp ./user.yaml "$USER_FILE"
  chmod 600 "$USER_FILE"
  chown root:root "$USER_FILE"
elif [ ! -f "$USER_FILE" ]; then
  log_error "user.yaml not provided and ${USER_FILE} does not exist."
  exit 1
else
  log_info "${USER_FILE} already exists; keeping current version."
fi
echo

# ======================
# Step 3: Install cert.pem if provided
# ======================
CURRENT_STEP=$((CURRENT_STEP+1))
log_step "Install cert.pem if provided"
if [ -f ./cert.pem ]; then
  log_info "Installing cert.pem -> ${CERT_PEM}"
  cp ./cert.pem "$CERT_PEM"
  chmod 600 "$CERT_PEM"
  chown root:root "$CERT_PEM"
elif [ ! -f "$CERT_PEM" ]; then
  log_warn "cert.pem not found (no new file and none installed). Skipping."
else
  log_info "${CERT_PEM} already exists; keeping current version."
fi
echo

# ======================
# Step 4: Install all MIL packages if available
# ======================
CURRENT_STEP=$((CURRENT_STEP+1))
log_step "Install MIL packages if available"
MIL_PACKAGES_DIR="${SCRIPT_DIR}/MIL_packages"
if [ -d "$MIL_PACKAGES_DIR" ]; then
  shopt -s nullglob
  mil_debs=( "$MIL_PACKAGES_DIR"/*.deb )
  shopt -u nullglob

  if [ "${#mil_debs[@]}" -gt 0 ]; then
    log_info "Installing ${#mil_debs[@]} MIL package(s) from ${MIL_PACKAGES_DIR}"
    if command -v apt-get >/dev/null 2>&1; then
      DEBIAN_FRONTEND=noninteractive apt-get install -y "${mil_debs[@]}"
    else
      dpkg -i "${mil_debs[@]}"
    fi
    log_info "MIL package installation complete."
  else
    log_info "${MIL_PACKAGES_DIR} exists but contains no .deb files; skipping MIL packages."
  fi
else
  log_info "No MIL_packages directory found; skipping MIL packages."
fi
echo

# ======================
# Step 5: Install DLM package if available
# ======================
CURRENT_STEP=$((CURRENT_STEP+1))
log_step "Install DLM package if available"
if ls ./moxa-dlm-agent*.deb >/dev/null 2>&1; then
  log_info "Installing local package ./moxa-dlm-agent*.deb via apt-get"
  DEBIAN_FRONTEND=noninteractive apt-get install -y ./moxa-dlm-agent*.deb > /dev/null
  log_info "DLM package installation complete."
else
  log_info "No local moxa-dlm-agent*.deb found; skipping package install."
fi
echo

# ======================
# Step 6: Import or keep credentials
# ======================
CURRENT_STEP=$((CURRENT_STEP+1))
log_step "Import or keep credentials.yaml"
if [ -f ./credentials.yaml ]; then
  if ! command -v mx-dlm-agent >/dev/null 2>&1; then
    log_error "mx-dlm-agent not found in PATH; cannot import credentials."
    exit 1
  fi
  log_info "Importing credentials.yaml (tool will encrypt & store securely)"
  mx-dlm-agent import -f ./credentials.yaml
  # Best-effort cleanup if file still exists after import
  if [ -f ./credentials.yaml ]; then
    shred -u ./credentials.yaml || rm -f ./credentials.yaml || true
    log_info "Removed plaintext ./credentials.yaml after import."
  fi
elif [ ! -f "$CREDENTIALS_ENC" ]; then
  log_error "credentials.yaml not provided and ${CREDENTIALS_ENC} not found."
  exit 1
else
  log_info "${CREDENTIALS_ENC} already exists; keeping current version."
fi
echo

# ======================
# Step 7: Enable & restart service
# ======================
CURRENT_STEP=$((CURRENT_STEP+1))
log_step "Reload systemd, enable and restart agent service"
systemctl daemon-reload || true
systemctl enable "$AGENT_SERVICE" || true
systemctl restart "$AGENT_SERVICE" || true
log_info "Service ${AGENT_SERVICE} restarted."
echo

# ======================

# Step 7: Optional update for Moxa Connection Manager (MCM)
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd -P)"
MCM_DIR="${SCRIPT_DIR}/MCM"

if [ -d "${MCM_DIR}" ]; then
  shopt -s nullglob
  debs=( "${MCM_DIR}"/*.deb )
  if [ "${#debs[@]}" -gt 0 ]; then
    echo "Detected Moxa Connection Manager (MCM) update packages: ${#debs[@]} .deb file(s). Installing..."
    if command -v apt-get >/dev/null 2>&1; then
      set +e
      apt-get -y install "${debs[@]}"
      rc=$?
      set -e
      if [ $rc -ne 0 ]; then
        echo "apt installation failed, falling back to dpkg + dependency fix..."
        dpkg -i "${debs[@]}" || true
        apt-get -y -o APT::Install-Recommends="false" install -f
      fi
    else
      dpkg -i "${debs[@]}"
    fi
    echo "Moxa Connection Manager (MCM) update complete."
  else
    echo "MCM directory exists but contains no .deb files, skipping MCM installation."
  fi
else
  echo "No MCM update directory detected, skipping MCM installation."
fi

# ======================
# Step 8: Verify enrollment status (friendly interpretation)
# ======================
# The raw `mx-dlm-agent status` is terse, so we read it here and explain what it
# means and what to do next — so the installer doesn't have to decode it manually.

read_status() {
  local raw lc
  raw="$(mx-dlm-agent status 2>/dev/null || true)"
  lc="$(printf '%s' "$raw" | tr '[:upper:]' '[:lower:]')"
  if   printf '%s' "$lc" | grep -q "not running"; then echo "notrunning"
  elif printf '%s' "$lc" | grep -q "error";        then echo "error"
  elif printf '%s' "$lc" | grep -q "disconnected"; then echo "disconnected"
  elif printf '%s' "$lc" | grep -q "pending";      then echo "pending approval"
  elif printf '%s' "$lc" | grep -q "provisioning"; then echo "provisioning"
  elif printf '%s' "$lc" | grep -q "connecting";   then echo "connecting"
  elif printf '%s' "$lc" | grep -q "connected";    then echo "connected"
  elif printf '%s' "$lc" | grep -q "enroll";       then echo "enroll"
  elif printf '%s' "$lc" | grep -q "init";         then echo "init"
  else echo "${raw:-}"; fi
}

explain_status() {
  case "$1" in
    connected)
      log_info "${GREEN}CONNECTED — the device is enrolled and managed by DLM.${RESET}" ;;
    "pending approval")
      log_warn "PENDING APPROVAL — registered, waiting for an admin to approve."
      echo    "         → Approve it in the DLM web console:  Device Approval" ;;
    provisioning)
      log_info "PROVISIONING — approved; the server is applying settings. Please wait." ;;
    enroll|connecting)
      log_info "IN PROGRESS (${1}) — normal transient state; give it a few more seconds." ;;
    init)
      log_warn "INIT — initializing and trying to reach the DLM server."
      echo    "         If it stays at 'init', the device cannot reach the server. Check:"
      echo    "           • Network / Internet  (try:  ping ${DLM_HOST:-<your-server-fqdn>} )"
      echo    "           • 'dlmServer.host' in user.yaml is the correct FQDN (NO https:// prefix)" ;;
    disconnected)
      log_warn "DISCONNECTED — lost connection to the DLM server."
      echo    "         → Check the network, then:  systemctl status ${AGENT_SERVICE}" ;;
    error)
      log_error "ERROR during enrollment/registration."
      echo    "         → Run:  systemctl status ${AGENT_SERVICE}"
      echo    "           Common causes: wrong credentials/password, or a bad user.yaml." ;;
    notrunning|"")
      log_error "The agent daemon does not appear to be running."
      echo    "         → Run:  systemctl status ${AGENT_SERVICE}" ;;
    *)
      log_info "Current status: ${BOLD}$1${RESET}" ;;
  esac
}

echo -e "${CYAN}${BOLD}Verifying enrollment status...${RESET}"
# Read the configured server host for nicer hints (best-effort)
DLM_HOST="$(awk -F'\"' '/host:/{print $2; exit}' "$USER_FILE" 2>/dev/null || true)"

# Poll a few times; the service was just (re)started and needs a moment to settle.
set +e
ST=""
for _i in 1 2 3 4 5 6; do
  ST="$(read_status)"
  case "$ST" in connected|error|disconnected|notrunning|"pending approval") break ;; esac
  sleep 2
done
set -e
echo

# ======================
# Summary
# ======================
sep
if [ "$ST" = "connected" ]; then
  echo -e "${GREEN}${BOLD}Installation complete — device is CONNECTED.${RESET}"
else
  echo -e "${GREEN}${BOLD}Installation complete.${RESET}  Enrollment status: ${BOLD}${ST:-unknown}${RESET}"
fi
explain_status "$ST"
echo
echo -e "  ${DIM}Re-check any time:${RESET}            mx-dlm-agent status"
echo -e "  ${DIM}Service health:${RESET}               systemctl status ${AGENT_SERVICE}"
echo -e "  ${DIM}Collect logs for Moxa Support:${RESET} ./collect_dlm_logs.sh"
sep
echo
